Kernel Hardening#
The kernel is the core of the operating system and is unfortunately very prone to attacks. Therefore, it is very important to take care to harden it well.
Choosing a kernel release#
The Linux kernel is released under two main forms: stable and long-term support (LTS). Stable releases are more recent, whereas LTS releases are an older stable release that is being supported for a long time.
Unfortunately, most security fixes cannot be ported from stable to LTS releases. Although many more security fixes are included in stable releases of the kernel, many new features are also introduced, which often introduce new vulnerabilities and bugs.
As practice shows, LTS kernels offer more stability and security. If you're not using very recent hardware, or you don't need some of the new features from the stable releases, then the better solution is to use the LTS kernel.
LTS releases of Ubuntu (20.04 or 22.04, for example) already using LTS kernel by default.
Update databases and packages:
sudo pacman -Suy
Install LTS kernel itself:
sudo pacman -S linux-lts linux-lts-headers
Uninstall stable kernel release:
sudo pacman -Rsn linux linux-headers
Generate initramfs:
sudo mkinitcpio -P
Update GRUB config to make it able to see the new kernel:
sudo grub-mkconfig -o /boot/grub/grub.cfg
Reboot your server:
sudo reboot
Kernel options#
The sysctl utility is used to change kernel parameters, allowing you to disable dangerous functions and enable security features. To make temporary changes, you can run:
sudo sysctl -w <parameter>=<value>
Where <parameter> -- is the target parameter and
<value> -- is the desired value.
To make changes on a permanent basis,
they need to be added to the /etc/sysctl.conf file:
sudo -e /etc/sysctl.conf
The following are the recommended sysctl settings that you should change.
Kernel self-protection#
kernel.kptr_restrict = 2
A kernel pointer points to a specific location in kernel memory. These can be very useful in exploiting the kernel, but kernel pointers are not hidden by default -- it is easy to uncover them by, for example, reading the contents of /proc/kallsyms. This setting aims to mitigate kernel pointer leaks. Alternatively, you can set value to 1 to only hide kernel pointers from processes without the CAP_SYSLOG capability and non-root users.
kernel.dmesg_restrict = 1
Dmesg is a kernel log. It often leaks a lot of sensitive information. The setting above restricts log retrieval to root user and processes with CAP_SYSLOG capability.
kernel.printk = 3 3 3 3
Despite the value of dmesg_restrict,
the kernel log will still be displayed in the console during boot.
Malware that is able to record the screen during boot may be able to
abuse this to gain higher privileges.
This option prevents those information leaks.
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2
These options restrict usage of eBPF to the CAP_BPF capability and enable some JIT hardening techniques.
dev.tty.ldisc_autoload = 0
Restrict to CAP_SYS_MODULE capability line discipline autoloading that is in a kernel module when a user asks for it to be loaded with the TIOCSETD ioctl. More information there.
vm.unprivileged_userfaultfd = 0
The userfaultfd() syscall is often abused, so, due to this, this parameter is used to restrict this syscall to the CAP_SYS_PTRACE capability.
kernel.kexec_load_disabled = 1
Kexec is a system call that is used to boot another kernel during runtime. This functionality can be abused to load a malicious kernel and gain arbitrary code execution in kernel mode, so this parameter disables it.
kernel.sysrq = 4
The SysRq key exposes a lot of potentially dangerous debugging functionality to unprivileged users. The value of this parameter makes it so that a user can only use the secure attention key, which will be necessary for accessing root user securely. Alternatively, you can simply set the value to 0 to disable SysRq completely.
kernel.unprivileged_userns_clone = 0
User namespaces are a feature in the kernel which aim to improve sandboxing and make it easily accessible for unprivileged users. However, this feature exposes significant kernel attack surface for privilege escalation, so this parameter restricts the usage of user namespaces to the CAP_SYS_ADMIN capability. This will prevent Docker from running in rootless mode.
Be aware though that this parameters only exists on certain Linux distributions, as it requires a kernel patch. It presists on Ubuntu 20.04, Ubuntu 22.04 and Arch Linux.
kernel.perf_event_paranoid = 3
Performance events can leak sensitive information and cause abundant vulnerabilities. This parameter restricts all usage of performance events to the CAP_PERFMON capability.
vm.panic_on_oom = 1
kernel.panic = 30
kernel.panic_on_oops = 30
These parameters enable automatic reboot in 30 seconds after a kernel panic and enables causing kernel panic by out-of-memory conditions.
Network#
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096
These help protect against SYN flood attacks, which are a form of denial-of-service attack, in which an attacker sends a large amount of bogus SYN requests in an attempt to consume enough resources to make the system unresponsive to legitimate traffic.
net.ipv4.tcp_rfc1337 = 1
This protects against time-wait assassination by dropping RST packets for sockets in the time-wait state.
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
These enable source validation of packets received from all interfaces of the machine. This protects against IP spoofing, in which an attacker sends a packet with a fraudulent IP address.
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects=0
These disable ICMP redirect acceptance and sending to prevent man-in-the-middle attacks and minimise information disclosure.
net.ipv4.icmp_echo_ignore_all = 1
This setting makes your system ignore all ICMP requests to avoid Smurf attacks, make the device more difficult to enumerate on the network and prevent clock fingerprinting through ICMP timestamps.
net.ipv4.tcp_timestamps = 0
This parameter disables TCP timestamps to prevent clock fingerprinting.
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
Source routing is a mechanism that allows users to redirect network traffic. As this can be used to perform man-in-the-middle attacks in which the traffic is redirected for nefarious purposes, the above settings disable this functionality.
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
Malicious IPv6 router advertisements can result in a man-in-the-middle attack, so they should be disabled.
net.ipv4.tcp_sack = 0
net.ipv4.tcp_dsack = 0
net.ipv4.tcp_fack = 0
This disables TCP SACK. SACK is commonly exploited and unnecessary in many circumstances, so it should be disabled if it is not required.
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
Privacy Extension is replacing the static interface ID (mostly based on word-wide unique MAC address) used during autoconfiguration by a pseudo-random one and generating from time to time a new one deprecating the old one.
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
There enables logging of suspicious packets.
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
These disable acceptance of source-routed packets. Under normal routing circumstances, an attacker from the Internet routable addresses could not use the system as a way to reach the private address systems. If, however, source routed packets were allowed, they could be used to gain access to the private address systems as the route could be specified, rather than rely on routing protocols that did not allow this routing.
net.ipv4.tcp_fin_timeout = 30
This specifies how many seconds to wait for a final FIN packet before the socket is forcibly closed. Required to prevent denial-of-service attacks.
Userspace#
kernel.yama.ptrace_scope = 2
Ptrace is a system call that allows a program to alter and inspect another running process, which allows attackers to trivially modify the memory of other running programs. This restricts usage of ptrace to only processes with the CAP_SYS_PTRACE capability. Alternatively, set the sysctl to 3 to disable ptrace entirely.
vm.mmap_rnd_bits = 32
vm.mmap_rnd_compat_bits = 16
ASLR is a common exploit mitigation which randomises the position of critical parts of a process in memory. This can make a wide variety of exploits harder to pull off, as they first require an information leak. The above settings increase the bits of entropy used for mmap ASLR, improving its effectiveness.
The values of these sysctls must be set in relation to the CPU architecture. The above values are compatible with x86(_64), but other architectures may differ.
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
This only permits symlinks to be followed when outside of a world-writable sticky directory, when the owner of the symlink and follower match or when the directory owner matches the symlink's owner. This also prevents hardlinks from being created by users that do not have read/write access to the source file.
fs.protected_fifos = 2
fs.protected_regular = 2
These prevent creating files in potentially attacker-controlled environments, such as world-writable directories, to make data spoofing attacks more difficult.
Blacklisting unneeded kernel modules#
The kernel allows unprivileged users to indirectly cause certain modules to be loaded via module auto-loading. This allows an attacker to auto-load a vulnerable module which is then exploited.
Specific kernel modules can be blacklisted by inserting files into /etc/modprobe.d with instructions on which kernel modules to blacklist.
The install parameter tells modprobe to run a specific command instead of loading the module as normal. /bin/false is a command that simply returns 1, which will essentially do nothing. Both of these together tells the kernel to run /bin/false instead of loading the module, which will prevent the module from being exploited by attackers.
Open the file /etc/modprobe.d/blacklist.conf:
sudo -e /etc/modprobe.d/blacklist.conf
Below are modules that can make your system vulnerable and are probably unnecessary. If any of the modules you need -- just do not add a line with it in the file.
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
install n-hdlc /bin/false
install ax25 /bin/false
install netrom /bin/false
install x25 /bin/false
install rose /bin/false
install decnet /bin/false
install econet /bin/false
install af_802154 /bin/false
install ipx /bin/false
install appletalk /bin/false
install psnap /bin/false
install p8023 /bin/false
install p8022 /bin/false
install can /bin/false
install atm /bin/false
Obscure networking protocols in particular add considerable remote attack surface. This blacklists:
DCCP — Datagram Congestion Control Protocol
SCTP — Stream Control Transmission Protocol
RDS — Reliable Datagram Sockets
TIPC — Transparent Inter-process Communication
HDLC — High-Level Data Link Control
AX25 — Amateur X.25
NetRom
X25
ROSE
DECnet
Econet
af_802154 — IEEE 802.15.4
IPX — Internetwork Packet Exchange
AppleTalk
PSNAP — Subnetwork Access Protocol
p8023 — Novell raw IEEE 802.3
p8022 — IEEE 802.2
CAN — Controller Area Network
ATM
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install squashfs /bin/false
install udf /bin/false
This blacklists various rare filesystems.
install cifs /bin/true
install nfs /bin/true
install nfsv3 /bin/true
install nfsv4 /bin/true
install ksmbd /bin/true
install gfs2 /bin/true
Network filesystems can also be blacklisted if not in use.
install vivid /bin/false
The vivid driver is only useful for testing purposes and has been the cause of privilege escalation vulnerabilities, so it should be disabled.
install bluetooth /bin/false
install btusb /bin/false
This disables Bluetooth, which has a history of security issues.